home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 / SpriteWorld files / Utils / Brian's Extensions / SWTinting.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-31  |  10.9 KB  |  352 lines  |  [TEXT/CWIE]

  1. /*  -----------------------------------------------------------------------------------
  2.     -----------------------------------------------------------------------------------
  3.     SWTinting.c
  4.     
  5.     by Brian Roddy
  6.     
  7.     4/3/97
  8.  
  9.  
  10.     - Functions for tinting SpriteWorld graphics a particular color.  
  11.     - Functions for using tinting to implement basic lighting techniques on 
  12.       sprites and tiles.
  13.  
  14.     This style of lighting works well with tiles with a single kind of light.  This
  15.     is because we precompute all of the sprites and tiles at the different light
  16.     levels.  This makes it fast, but not very flexible.  See "SWLightingSquares.c"
  17.     for another approach to lighting which is slightly slower, but is dynamic and
  18.     handles an arbitrary number of colored lights.
  19.  
  20.     This source code is available for free use.
  21.     
  22.     ----------------------------------------------------------------------------------- 
  23.     ----------------------------------------------------------------------------------- */
  24.  
  25. #include <QDOffScreen.h>
  26. #include "SpriteWorldUtils.h"
  27. #include "SWTinting.h"
  28.  
  29.  
  30. /*    --- SWTintFrame
  31.  
  32.     This function takes a frame and uses a color to tint the sprite's frame by some
  33.     percent.  The tint is specified by an RGBColor.  The percent is a number from 0-100.  
  34.     For instance, to lighten a sprite a little bit, use white as a color and 10 as a 
  35.     percent.
  36.     
  37.     These functions perform some basic error checking and will return the error if found.
  38.  
  39. */
  40.  
  41. SW_FUNC OSErr SWTintFrame (
  42.     FramePtr srcFrameP,
  43.     RGBColor* tint, 
  44.     float percent)
  45. {
  46.     GWorldPtr            oldGWld;
  47.     GDHandle            oldGDH;
  48.     GWorldFlags            pixelState;
  49.     RGBColor            opColor;
  50.     OSErr                 err = noErr;
  51.     
  52.     // Make sure we have an actual frame
  53.     if (srcFrameP->framePort == NULL)
  54.         err = paramErr;
  55.  
  56.     if (err == noErr) {
  57.         // Save all current information.
  58.         GetGWorld( &oldGWld, &oldGDH );
  59.     
  60.         // Save the pixel state of our bitmap's GWorld
  61.         pixelState = GetPixelsState( GetGWorldPixMap( srcFrameP->framePort ));
  62.         (void)LockPixels( GetGWorldPixMap( srcFrameP->framePort ));
  63.         SetGWorld( srcFrameP->framePort, NULL );
  64.  
  65.         // And then blend in the Sprite image it's appropriate percent.
  66.         // Opcolor specifies the amount of blend
  67.         opColor.red = opColor.blue = opColor.green = (((percent) * 65535.0) / 100.0);
  68.         OpColor(&opColor);
  69.  
  70.         // Paint the Sprite the color specified by tint.
  71.         RGBForeColor(tint);
  72.  
  73.         // Blend will do the work of tinting
  74.         PenMode(blend);
  75.         
  76.         // And then paint it to tint the frame.
  77.         // If there is a mask, then just tint the masked part of the frame.
  78.         if (srcFrameP->maskRgn != NULL)
  79.             PaintRgn(srcFrameP->maskRgn);
  80.         // Otherwise tint the entire frame
  81.         else
  82.             PaintRect(&srcFrameP->frameRect);
  83.         
  84.         //Restore the state of the world.
  85.         PenNormal();
  86.         SetPixelsState( GetGWorldPixMap( srcFrameP->framePort ), pixelState );
  87.         SetGWorld( oldGWld, oldGDH );
  88.     }
  89.  
  90.     SWSetStickyIfError( err );
  91.     return err;
  92. }
  93.  
  94. ///--------------------------------------------------------------------------------------
  95. ///--------------------------------------------------------------------------------------
  96. ///--------------------------------------------------------------------------------------
  97. /// Tile Light Level Functions
  98. ///--------------------------------------------------------------------------------------
  99. short backgroundTileMinimumLightLevel = 0;
  100.  
  101. /*    -- CreateTileBrightnessSetFromCicnResource --
  102.  
  103.     This function is the same as SWLoadTileFromCicnResource except that it will
  104.     create a set of tiles rather than one.  Each tile represents the original tile at a
  105.     different light level.  It uses the SWTintFrame to do this.  Each tile will
  106.     get successively brighter until reaching the original tile.
  107.     
  108. */
  109.  
  110. SW_FUNC OSErr CreateTileBrightnessSetFromCicnResource (
  111.     SpriteWorldPtr    swp,
  112.     short            baseTileID,
  113.     short            cicnID, 
  114.     MaskType        maskType) {
  115.     
  116.     OSErr         err = noErr;
  117.     RGBColor    tintColor;
  118.     int i;
  119.     float ratio;
  120.     
  121.     // Our tint color is black because we make darker versions of the tile
  122.     tintColor.red = tintColor.green = tintColor.blue = 0;
  123.     
  124.     // For each of the different light levels
  125.     for (i = 0; i < kNumberOfBrightnessLevels; i++) {
  126.         if (err == noErr) {
  127.             // Create tile normally            
  128.             err = SWLoadTileFromCicnResource(swp, baseTileID + i, cicnID, maskType);
  129.  
  130.             // And then tint it.
  131.             ratio = ((i + 1.0) / kNumberOfBrightnessLevels);
  132.             if ((err == noErr) && (ratio != 1.0)) {
  133.                 err = SWTintFrame(
  134.                             swp->tileFrameArray[baseTileID + i], 
  135.                             &tintColor,
  136.                             100 - (ratio * 100));
  137.             }
  138.         }
  139.     }
  140.     
  141.     SWSetStickyIfError( err );
  142.     return err;
  143. }
  144.  
  145.  
  146. ///--------------------------------------------------------------------------------------
  147. /// GetTileBrightnessLevel
  148. ///
  149. /// Returns a particular tile on the screens light level.
  150. /// Remember that the light level is encoded in the tile's id.
  151.  
  152. SW_FUNC int GetTileBrightnessLevel (SpriteWorldPtr swp, short tileLayer, int row, int col) {
  153.     int curTileID;
  154.         // Compute the current Light level by dividing by 
  155.         // kNumberOfBrightnessLevels and taking the remainder.
  156.     curTileID = swp->tileLayerArray[tileLayer]->tileMap[row][col];
  157.     return (curTileID % kNumberOfBrightnessLevels);
  158. }
  159.  
  160. ///--------------------------------------------------------------------------------------
  161. /// SetTileBrightnessLevel
  162. ///
  163. /// Sets the light level of a particular tile on the screens.
  164. /// Remember that the light level is encoded in the tile's id.
  165.  
  166. SW_FUNC void SetTileBrightnessLevel (SpriteWorldPtr swp, short tileLayer, int row, int col, 
  167.     int level, Boolean relative) {
  168.     int curTileID;
  169.     int oldLightLevel;
  170.     int tileWithoutLight;
  171.     int newLightLevel;
  172.     int newTileID;
  173.     
  174.     // Bounds checking of row and colums.
  175.     if (! ((row < 0) || 
  176.            (col < 0) || 
  177.            (row >= swp->tileLayerArray[tileLayer]->numRows) ||
  178.            (col >= swp->tileLayerArray[tileLayer]->numCols)) ) {
  179.         
  180.         // Given the current TileID
  181.         curTileID = swp->tileLayerArray[tileLayer]->tileMap[row][col];
  182.         
  183.         // Compute the current Light level by dividing by 
  184.         // kNumberOfBrightnessLevels and taking the remainder.
  185.         oldLightLevel = curTileID % kNumberOfBrightnessLevels;
  186.         
  187.         // Subtracting the remainder will leave us with the
  188.         // tile id without light (i.e. the tile at light level zero)
  189.         tileWithoutLight = curTileID - oldLightLevel;
  190.         
  191.         // If relative, add the new level to the old.
  192.         // Of course if the new level is negative it will lower the light.
  193.         if (relative) 
  194.             newLightLevel = oldLightLevel + level;
  195.         else
  196.         // Otherwise, set the light to the maximum of the new or the old.
  197.             newLightLevel = ((level > oldLightLevel) ? level : oldLightLevel);
  198.             
  199.         // Bounds checking of light level
  200.         if (newLightLevel < 0) 
  201.             newLightLevel = 0;
  202.         else if (newLightLevel >= kNumberOfBrightnessLevels) {
  203.             newLightLevel = kNumberOfBrightnessLevels - 1;
  204.         }
  205.         if (newLightLevel < backgroundTileMinimumLightLevel)
  206.             newLightLevel = backgroundTileMinimumLightLevel;
  207.         
  208.         // Compute the new  tile ID  by combining our raw tile id and
  209.         // the new light level. 
  210.         newTileID = tileWithoutLight + newLightLevel;
  211.         swp->tileLayerArray[tileLayer]->tileMap[row][col] = newTileID;
  212.  
  213.         // Then redraw the tile
  214.         SWDrawTile(swp, tileLayer, row, col, newTileID);
  215.     }
  216.     return;
  217. }
  218.  
  219. ///--------------------------------------------------------------------------------------
  220. ///---- LowerTileBrightnessLevels.
  221. ///
  222. /// A utility function to do light fading over time.  Looks pretty neat.
  223.  
  224. SW_FUNC void LowerTileBrightnessLevels (SpriteWorldPtr swp) {
  225.     short    tileRow, tileCol, tileLayer;
  226.     int     numrows = swp->tileLayerArray[0]->numRows;
  227.     int     numcols = swp->tileLayerArray[0]->numCols;
  228.     
  229.         // Go through every TileMap in the SpriteWorld
  230.     for (tileLayer = 0; tileLayer <= swp->lastActiveTileLayer; tileLayer++)
  231.     {
  232.         if (swp->tileLayerArray[tileLayer] == NULL)
  233.             continue;
  234.             
  235.             // Go through every row
  236.         for (tileRow = 0; tileRow < numrows; tileRow++)
  237.         {
  238.                 // and column in the tile map
  239.             for (tileCol = 0; tileCol < numcols; tileCol++)
  240.             {
  241.                     // and lower it by 1.
  242.                 if (GetTileBrightnessLevel(swp, tileLayer, tileRow, tileCol) > 
  243.                     backgroundTileMinimumLightLevel)
  244.                 {
  245.                     SetTileBrightnessLevel(swp, tileLayer, tileRow, tileCol, -1, true);
  246.                 }
  247.             }
  248.         }
  249.     }
  250. }
  251.  
  252.  
  253.  
  254.  
  255. ///--------------------------------------------------------------------------------------
  256. ///--------------------------------------------------------------------------------------
  257. ///--------------------------------------------------------------------------------------
  258. // Sprite Light Level Functions.
  259. ///--------------------------------------------------------------------------------------
  260.  
  261.  
  262. /*    -- CreateSpriteBrightnessSetFromCicnResource --
  263.  
  264.     This function is the same as SWCreateSpriteFromCicnResource except that it will
  265.     create multiple frames for the same sprite where each frame represents a
  266.     different light level.  It uses SWTintFrame to do this.  Each frame will
  267.     get successively brighter until reaching the original sprite's light level.
  268.     
  269. */
  270.  
  271. // Note that this code is a modified version of SWCreateSpriteFromCicnResource.
  272. SW_FUNC OSErr CreateSpriteBrightnessSetFromCicnResource (
  273.     SpriteWorldPtr destSpriteWorld,
  274.     SpritePtr* newSpriteP,
  275.     void* spriteStorageP,
  276.     short cIconID,
  277.     MaskType maskType) {
  278.     
  279.     OSErr             err;
  280.     SpritePtr         tempSpriteP;
  281.     FramePtr         newFrameP;
  282.     short             frame;
  283.     
  284.     // Change #1: Our two new variables
  285.     RGBColor        tintColor;
  286.     float             ratio;
  287.  
  288.     // Change #2: We specify a Tint Color.
  289.     // Our tint color is black because we make are making 
  290.     // darker versions of the sprite
  291.     tintColor.red = tintColor.green = tintColor.blue = 0;
  292.     
  293.     *newSpriteP = NULL;
  294.  
  295.     err = SWCreateSprite(&tempSpriteP, spriteStorageP, kNumberOfBrightnessLevels);
  296.     
  297.     if (err == noErr)
  298.     {
  299.         // Change #3: number of frames we make is kNumberOfBrightnessLevels
  300.         // That is, one frame per brightness level
  301.         for (frame = 0; frame < kNumberOfBrightnessLevels; frame++)
  302.         {
  303.             err = SWCreateFrameFromCicnResource(
  304.                     destSpriteWorld, 
  305.                     &newFrameP, 
  306.                     cIconID, // Change #4: All sprites use the same cicn.
  307.                     maskType);
  308.  
  309.             if (err == noErr) 
  310.                 err = SWAddFrame(tempSpriteP, newFrameP);
  311.  
  312.             // Change #5: Here we do the actual tinting.  We calculate
  313.             // the current percent of brightness and call our tinting
  314.             // function.
  315.             ratio = ((frame + 1.0) / kNumberOfBrightnessLevels);
  316.             if ((err == noErr) && (ratio != 1.0))
  317.                 err = SWTintFrame(
  318.                             tempSpriteP->frameArray[frame], 
  319.                             &tintColor,
  320.                             100 - (ratio * 100));
  321.  
  322.             if (err != noErr)
  323.             {
  324.                 SWDisposeFrame(&newFrameP);
  325.                 SWDisposeSprite(&tempSpriteP);
  326.                 break;
  327.             }
  328.         }
  329.  
  330.         if (err == noErr)
  331.         {
  332.             SWSetSpriteFrameRange(tempSpriteP, 0, kNumberOfBrightnessLevels - 1);
  333.             SWSetCurrentFrameIndex(tempSpriteP, 0);
  334.             *newSpriteP = tempSpriteP;
  335.         }
  336.     }
  337.  
  338.     SWSetStickyIfError( err );
  339.     return err;
  340. }
  341.  
  342. ///--------------------------------------------------------------------------------------
  343. /// The Light Level is encoded in the frame index, so setting and getting it is easy.
  344. SW_FUNC int GetSpriteBrightnessLevel (SpritePtr spriteP) {
  345.     return spriteP->curFrameIndex;
  346. }
  347.  
  348. SW_FUNC void SetSpriteBrightnessLevel (SpritePtr spriteP, int tileLightLevel) {
  349.     SWSetCurrentFrameIndex(spriteP, tileLightLevel);
  350.     return;
  351. }
  352.